const path = require('path');
const webpack = require('webpack');
const WebpackBar = require('webpackbar');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const Config = require('webpack-chain');
const { DefaultBabelOptions } = require('@vocjs/bundler-babel');

const config = new Config();

let NODE_ENV = process.env.NODE_ENV || 'development';
NODE_ENV = NODE_ENV.trim();

const devMode = NODE_ENV !== 'production';

config.context(path.resolve(process.cwd()));

/* 1.开发环境 */
config.mode(NODE_ENV);

/* 2.入口配置 */
config.entry('lic').merge(['./src/pages/index']);
config.entry('fine').merge(['./src/pages/fine']);

/* 3.输出配置 */
config.output.path(path.resolve(__dirname, 'dist')).filename('js/[name].js').publicPath('.').end();

/* 4.devServer */
if (devMode) {
  config.devtool('inline-source-map');
  const dfc = {
    // disableHostCheck: true,
    // host:'localhost',
    port: 9000,
    hot: true,
    // open: true,
    // openPage: ['client.html'],
    noInfo: true,
    contentBase: [path.resolve('public'), path.join(__dirname, 'dist')],
    // compress: true,
    // inline: true,
    // historyApiFallback: true,
  };
  config.devServer.merge(dfc);
}

/* 5.module */
const babelOpts = new DefaultBabelOptions();
// todo cssModules 自动启动无效
babelOpts.tap(() => ({ isTS: true, isReact: true, isAntd: true, cssModules: { query: 'modules' } }));
babelOpts.preset('env').tap((options) => ({ ...options }));
babelOpts
  .plugin('@babel/plugin-proposal-class-properties')
  .use('@babel/plugin-proposal-class-properties')
  .options({ loose: true });

babelOpts.plugin('@vocjs/babel-plugin-auto-css-modules').use('@vocjs/babel-plugin-auto-css-modules');
// console.log('babelOpts', babelOpts.toString());

config.module
  .rule('ts')
  .test(/\.[jt]sx?$/)
  .include.add(/src/)
  .end()
  .exclude.add(/node_modules/)
  .end()
  .use('babel-loader')
  .loader('babel-loader')
  .options(babelOpts.toConfig());

/** *
 * 添加样式规则
 * @param webpackConfig
 * @param ruleConfig
 * @param devMode
 */
const addCSSRule = (webpackConfig, ruleConfig, devMode = false) => {
  const { name, test, loader, options } = ruleConfig;
  const baseRule = webpackConfig.module.rule(name).test(test);
  const modulesRule = baseRule.oneOf('modules').resourceQuery(/modules/);
  const normalRule = baseRule.oneOf('normal');

  const applyLoaders = (rule, cssModules) => {
    /* 1. 开发环境使用 style-loader ,生产环境使用 mini-css-extract-loader */
    rule.use('first-loader').when(
      devMode,
      (use) => {
        use
          .loader(require.resolve('style-loader'))
          .options({})
          .tap((preOptions) => ({ ...preOptions }));
      },
      (use) => {
        use
          .loader(MiniCssExtractPlugin.loader)
          .options({})
          .tap((preOptions) => ({ ...preOptions }));
      },
    );

    /* 2. css-loader */
    rule
      .use('css-loader')
      .loader(require.resolve('css-loader'))
      .options({
        importLoaders: loader ? 2 : 1,
        modules: cssModules
          ? {
              // localIdentName: '[local]_[hash:base64:5]',
              localIdentName: '[local]--[hash:base64:5]',
              exportLocalsConvention: 'camelCase',
            }
          : false,
        url: false,
      })
      .tap((preOptions) => ({ ...preOptions }));

    /* 3. postcss-loader */
    rule
      .use('postcss-loader')
      .loader(require.resolve('postcss-loader'))
      .options({
        plugins: (loader) => [
          require('postcss-import')({ root: loader.resourcePath }),
          require('postcss-preset-env')({
            autoprefixer: {
              grid: 'autoplace', // css grid 兼容IE浏览器
            },
          }),
          require('cssnano')({
            preset: ['default', {}],
          }),
          require('postcss-smart-asset')([
            {
              filter: '**/public/**/*',
              url: (asset) => `../${String(asset.url).replace(/public\//, '')}`,
            },
          ]),
        ],
      })
      .tap((preOptions) => ({ ...preOptions }));

    /* 4. less sass/scss stylus */
    if (loader) {
      rule.use(loader).loader(require.resolve(loader)).options(options);
    }
  };

  applyLoaders(modulesRule, true);
  applyLoaders(normalRule, false);
};

addCSSRule(config, { name: 'css', test: /\.css$/ }, devMode);
addCSSRule(
  config,
  { name: 'less', test: /\.less$/, loader: 'less-loader', options: { lessOptions: { javascriptEnabled: true } } },
  devMode,
);

/* 6.resolve */
config.resolve.extensions.merge(['.tsx', '.ts', '.js']).end().alias.set('@', path.resolve(__dirname, 'src')).end();

/* 7.plugins */
config.plugin('WebpackProgressBar').use(WebpackBar, [{}]);
config.plugin('CleanWebpackPlugin').use(CleanWebpackPlugin, [{}]).end();
config
  .plugin('HtmlWebpackPlugin')
  .use(HtmlWebpackPlugin, [
    {
      template: 'public/fine.html',
      filename: 'fine.html',
      favicon: 'public/favicon.ico',
      minify: 'auto',
      chunks: ['fine'],
    },
  ])
  .end();

config
  .plugin('MiniCssExtractPlugin')
  .use(MiniCssExtractPlugin, [{ filename: 'css/[name].css', chunkFilename: '[id].css' }])
  .end();

if (devMode) {
  config.plugin('HotModuleReplacementPlugin').use(webpack.HotModuleReplacementPlugin);
} else {
  config.plugin('CopyPlugin').use(CopyPlugin, [{ patterns: [{ from: 'public' }], options: { concurrency: 100 } }]);
}
config.plugin('custom-define').use(webpack.DefinePlugin, [
  {
    LIC_SERVER_HOST: JSON.stringify(process.env.LIC_SERVER_HOST || 'localhost'),
    LIC_SERVER_PORT: process.env.LIC_SERVER_PORT || 8189,
  },
]);

module.exports = config.toConfig();
